﻿#include "stdafx.h"
#include <cassert>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Function.h>
#include "../token.h"
#include "BinaryGen.h"
#include "utility.h"
#include "ClassInstanceType.h"

using namespace llvm;

BinaryGen::BinaryGen(int op, CodeGen * l, CodeGen * r)
{
	this->op = op;
	left = l;
	right = r;

	if (l->type->isDouble() || r->type->isDouble())
		type = AstType::doubleType;
	else
		type = AstType::floatType;
}

llvm::Value * BinaryGen::generateCode(Module *m, Function *function, IRBuilder<>&builder)
{
	Value* l = left->generateCode(m, function, builder);
	l = load(builder, l);
	Value* r = right->generateCode(m, function, builder);
	r = load(builder, r);

	if (l == nullptr || r == nullptr)
		throw std::runtime_error("二元操作符左右有空值");

	auto lty = l->getType();
	assert(!lty->isPointerTy());
	auto rty = r->getType();
	assert(!rty->isPointerTy());

	Type* dest;	// 目标格式（返回格式）
	int w = std::max(lty->getScalarSizeInBits(), rty->getScalarSizeInBits());

	if (type->isDouble()) {
		dest = Type::getDoubleTy(builder.getContext());
	}
	else {
		dest = Type::getFloatTy(builder.getContext());
	}

	// 操作数左右必须是相同类型，因此这里进行类型必要的转换
	l = try_cast(builder, dest, l);
	r = try_cast(builder, dest, r);

	switch (op) {
	case '+':
		return builder.CreateFAdd(l, r);
	case '-':
		return builder.CreateFSub(l, r);
	case '*':
		return builder.CreateFMul(l, r);
	case '/':
		return builder.CreateFDiv(l, r);
	case '>':
		return builder.CreateFCmpOGT(l, r);
	case '<':
		return builder.CreateFCmpOLT(l, r);
	case EQ:	// ==
		return builder.CreateFCmpOEQ(l, r);
	case NOEQ:	// !=
		return builder.CreateFCmpONE(l, r);
	case REQ:	// >=
		return builder.CreateFCmpOGE(l, r);
	case LEQ:	// <=
		return builder.CreateFCmpOLE(l, r);
	default:
		throw std::runtime_error("不支持的浮点运算符：" + operator_to_str(op));
	}
}

